#include "LexicalUnitImpl.h"
#include <assert.h>
#include <string>
#include <stdlib.h>

LexicalUnitImpl::LexicalUnitImpl()
    :m_UnitType(LexicalUnit::SAC_UNKNOWN),
    dimension(NULL), functionName(NULL), parameters(NULL),
    stringValue(NULL), previousLexicalUnit(NULL), nextLexicalUnit(NULL)
{

}

LexicalUnitImpl::LexicalUnitImpl(LexicalUnit* pre, LexicalUnitType type)
    :m_UnitType(type), dimension(NULL), functionName(NULL), parameters(NULL),
    stringValue(NULL), previousLexicalUnit(pre), nextLexicalUnit(NULL)
{
    if(pre)
    {
        this->nextLexicalUnit = ((LexicalUnitImpl*)pre)->nextLexicalUnit;
        ((LexicalUnitImpl*)pre)->nextLexicalUnit = this;
    }
}

LexicalUnitImpl::LexicalUnitImpl(LexicalUnit* pre, int value)
    :m_UnitType(LexicalUnit::SAC_INTEGER), dimension(NULL), functionName(NULL),
    parameters(NULL), stringValue(NULL), previousLexicalUnit(pre),
    nextLexicalUnit(NULL)
{
    if(pre)
    {
        this->nextLexicalUnit = ((LexicalUnitImpl*)pre)->nextLexicalUnit;
        ((LexicalUnitImpl*)pre)->nextLexicalUnit = this;
    }
    floatvalue = (float)value;
}


LexicalUnitImpl::LexicalUnitImpl(LexicalUnit* pre, LexicalUnitType type, float value)
    :m_UnitType(type), dimension(NULL), functionName(NULL), parameters(NULL),
    stringValue(NULL), previousLexicalUnit(pre), nextLexicalUnit(NULL)
{
    if(pre)
    {
        this->nextLexicalUnit = ((LexicalUnitImpl*)pre)->nextLexicalUnit;
        ((LexicalUnitImpl*)pre)->nextLexicalUnit = this;
    }
    floatvalue = value;
}

LexicalUnitImpl::LexicalUnitImpl(LexicalUnit* pre, LexicalUnitType type,
                                 const string& dim, float value)
    :m_UnitType(type), dimension(new string(dim)), functionName(NULL),
    parameters(NULL), stringValue(NULL), previousLexicalUnit(pre),
    nextLexicalUnit(NULL)
{
    if(pre)
    {
        this->nextLexicalUnit = ((LexicalUnitImpl*)pre)->nextLexicalUnit;
        ((LexicalUnitImpl*)pre)->nextLexicalUnit = this;
    }
    floatvalue = value;
}

LexicalUnitImpl::LexicalUnitImpl(LexicalUnit* pre, LexicalUnitType type,
                                 const string& value)
    :m_UnitType(type), dimension(NULL), functionName(NULL), parameters(NULL),
    stringValue(new string(value)), previousLexicalUnit(pre), nextLexicalUnit(NULL)
{
    if(pre)
    {
        this->nextLexicalUnit = ((LexicalUnitImpl*)pre)->nextLexicalUnit;
        ((LexicalUnitImpl*)pre)->nextLexicalUnit = this;
    }
}

LexicalUnitImpl::LexicalUnitImpl(LexicalUnit* pre, LexicalUnitType type,
                                 const string& name, LexicalUnit* params)
    :m_UnitType(type), dimension(NULL), functionName(new string(name)),
    parameters(params), stringValue(NULL), previousLexicalUnit(pre),
    nextLexicalUnit(NULL)
{
    if(pre)
    {
        this->nextLexicalUnit = ((LexicalUnitImpl*)pre)->nextLexicalUnit;
        ((LexicalUnitImpl*)pre)->nextLexicalUnit = this;
    }
}


LexicalUnitImpl::~LexicalUnitImpl()
{
	if(dimension)
		delete dimension;
	if(functionName)
		delete functionName;
	if(parameters)
	{
		LexicalUnit* p = parameters;
		while(p)
		{
			delete p;
			p = ((LexicalUnitImpl*)p)->nextLexicalUnit;
		}
	}
	if(stringValue)
		delete stringValue;
	if(previousLexicalUnit)
	{
		((LexicalUnitImpl*)previousLexicalUnit)->nextLexicalUnit =
		                   this->nextLexicalUnit;
	}
	if(nextLexicalUnit)
	{
		((LexicalUnitImpl*)nextLexicalUnit)->previousLexicalUnit =
							this->previousLexicalUnit;
	}
}

LexicalUnit::LexicalUnitType LexicalUnitImpl::getLexicalUnitType()const
{
    return m_UnitType;
}

LexicalUnit* LexicalUnitImpl::getNextLexicalUnit()const
{
    return nextLexicalUnit;
}

LexicalUnit* LexicalUnitImpl::getPreviousLexicalUnit()const
{
    return previousLexicalUnit;
}

int LexicalUnitImpl::getIntegerValue()const
{
    return (int)floatvalue;
}

float LexicalUnitImpl::getFloatValue()const
{
    return floatvalue;
}

string LexicalUnitImpl::getDimensionUnitText()const
{
    switch (m_UnitType)
    {
    case SAC_EM:
        return string("em");
    case SAC_EX:
        return string("ex");
    case SAC_PIXEL:
        return string("px");
    case SAC_INCH:
        return string("in");
    case SAC_CENTIMETER:
        return string("cm");
    case SAC_MILLIMETER:
        return string("mm");
    case SAC_POINT:
        return string("pt");
    case SAC_PICA:
        return string("pc");
    case SAC_PERCENTAGE:
        return string("%");
    case SAC_DEGREE:
        return string("deg");
    case SAC_GRADIAN:
        return string("grad");
    case SAC_RADIAN:
        return string("rad");
    case SAC_MILLISECOND:
        return string("ms");
    case SAC_SECOND:
        return string("s");
    case SAC_HERTZ:
        return string("Hz");
    case SAC_KILOHERTZ:
        return string("kHz");
    case SAC_DIMENSION:
		assert(dimension);
        return *dimension;
    default:
        break;
    }
    return string("");
}

string LexicalUnitImpl::getFunctionName()const
{
    if(functionName)
        return *functionName;
    return string("");
}

LexicalUnit* LexicalUnitImpl::getParameters()const
{
    return parameters;
}

string LexicalUnitImpl::getStringValue()const
{
    if(stringValue)
        return *stringValue;
    return string("");
}

LexicalUnit* LexicalUnitImpl::getSubValues()const
{
    return parameters;
}

const string* LexicalUnitImpl::toString()const
{
    string* result = NULL;
    try
    {
        result = new string;
        switch (m_UnitType)
        {
        case SAC_OPERATOR_COMMA:
            result->append(",");
            break;
        case SAC_OPERATOR_PLUS:
			result->append("+");
            break;
        case SAC_OPERATOR_MINUS:
            result->append("-");
            break;
        case SAC_OPERATOR_MULTIPLY:
            result->append("*");
            break;
        case SAC_OPERATOR_SLASH:
            result->append("/");
            break;
        case SAC_OPERATOR_MOD:
            result->append("%");
            break;
        case SAC_OPERATOR_EXP:
            result->append("^");
            break;
        case SAC_OPERATOR_LT:
            result->append("<");
            break;
        case SAC_OPERATOR_GT:
            result->append(">");
            break;
        case SAC_OPERATOR_LE:
            result->append("<=");
            break;
        case SAC_OPERATOR_GE:
            result->append(">=");
            break;
        case SAC_OPERATOR_TILDE:
            result->append("~");
            break;
        case SAC_INHERIT:
            result->append("inherit");
            break;
        case SAC_INTEGER:
            result->append(trimFloat(getIntegerValue()));
            break;
        case SAC_REAL:
            result->append(trimFloat(getFloatValue()));
            break;
        case SAC_EM:
        case SAC_EX:
        case SAC_PIXEL:
        case SAC_INCH:
        case SAC_CENTIMETER:
        case SAC_MILLIMETER:
        case SAC_POINT:
        case SAC_PICA:
        case SAC_PERCENTAGE:
        case SAC_DEGREE:
        case SAC_GRADIAN:
        case SAC_RADIAN:
        case SAC_MILLISECOND:
        case SAC_SECOND:
        case SAC_HERTZ:
        case SAC_KILOHERTZ:
        case SAC_DIMENSION:
            result->append(trimFloat(getFloatValue()));
			result->append(getDimensionUnitText());
            break;
        case SAC_URI:
            result->append("url(");
            result->append(getStringValue());
            result->append(")");
            break;
        case SAC_COUNTER_FUNCTION:
            result->append("counter(");
            appendParams(*result, parameters);
            result->append(")");
            break;
        case SAC_COUNTERS_FUNCTION:
            result->append("counters(");
            appendParams(*result, parameters);
            result->append(")");
            break;
        case SAC_RGBCOLOR:
            result->append("rgb(");
            appendParams(*result, parameters);
            result->append(")");
            break;
        case SAC_IDENT:
            result->append(getStringValue());
            break;
        case SAC_STRING_VALUE:
            result->append("\"");
            result->append(getStringValue());
            result->append("\"");
            break;
        case SAC_ATTR:
            result->append("attr(");
            appendParams(*result, parameters);
            result->append(")");
            break;
        case SAC_RECT_FUNCTION:
            result->append("rect(");
            appendParams(*result, parameters);
            result->append(")");
            break;
        case SAC_UNICODERANGE:
            result->append(getStringValue());
            break;
        case SAC_SUB_EXPRESSION:
            result->append(getStringValue());
            break;
        case SAC_FUNCTION:
            result->append(getFunctionName());
            result->append("(");
            appendParams(*result, parameters);
            result->append(")");
            break;
		default:
			break;
        }
    }
    catch(std::exception& e)
    {
        if(result)
            delete result;
        return NULL;
    }
    return result;
}

string LexicalUnitImpl::trimFloat(float f)const
{
	char buf[20] = {0};
	gcvt(f, 15, buf);
	return string(buf);
}

void LexicalUnitImpl::appendParams(string& s, const LexicalUnit* first)const
{
	const LexicalUnit* l = first;
	while(l)
	{
		s.append(*(l->toString()));
		l = ((LexicalUnitImpl*)l)->getNextLexicalUnit();
	}
}









